﻿using Confluent.Kafka;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Test.EventBus2.Core.Extensions;

namespace Test.EventBus2.Core.SubscribeStores
{
    public class KafkaSubscribeStore: ISubscribeStore
    {
        private static ConcurrentBag<object> _handlers = new ConcurrentBag<object>();
        private static ConcurrentDictionary<string, Delegate> _handlerFunctions = new ConcurrentDictionary<string, Delegate>();

        private IServiceProvider _provider;

        public KafkaSubscribeStore(IServiceProvider provider)
        {
            _provider = provider;
        }

        public void AddHandler<TMssage>(IHandleMessages handler, Delegate callback)
        {
            var typeName = Shims.GetSimpleAssemblyQualifiedName(typeof(TMssage));
            _handlers.Add(handler);
            _handlerFunctions.GetOrAdd(typeName, callback); 

        }

        public Delegate GetMessageHandlerFunction(Type type) 
        {
            Delegate func;
            var typeName = Shims.GetSimpleAssemblyQualifiedName(type);
            _handlerFunctions.TryGetValue(typeName, out func);
            return func;

        }

        public List<IHandleMessages<TMessage>> GetMessageHandlersForMessage<TMessage>() 
        {
            var genicType = typeof(IHandleMessages<TMessage>);
            var handlers = FigureOutTypesToResolve(genicType)
                 .Select(type => _provider.GetServices(type).Cast<IHandleMessages>())
                 .Cast<IHandleMessages<TMessage>>().ToList();
            return handlers;

        }

        public List<IHandleMessages> GetMessageHandlersForMessage(Type type)
        {

            var handlers = FigureOutTypesToResolve(type)
                 .SelectMany(type => _provider.GetServices(type).Cast<IHandleMessages>()).ToList();
            return handlers;

        }

        static Type[] FigureOutTypesToResolve(Type messageType)
        {
            IEnumerable<Type> handledMessageTypes;

            if (messageType.GetInterfaces().Any(i => i.IsGenericType ))
            {
                var actualMessageType = messageType.GetGenericArguments()[0];
                handledMessageTypes = new[] { actualMessageType }.Concat(actualMessageType.GetBaseTypes()).Select(t => typeof(IHandleMessages<>).MakeGenericType(t));
            }
            else
            {
                handledMessageTypes = new[] { messageType }.Concat(messageType.GetBaseTypes());
            }

            return handledMessageTypes
                .Select(t => typeof(IHandleMessages<>).MakeGenericType(t))
                .ToArray();
        }
    }
}
